module dice.ui.sdl.sdl;

import dice.ui.gadget;
import dice.ui.container;
import dice.threading;
import dice.render.render;

import std.stdio;

/** A top level window */
class TopLevel : Container
{
	static const bool hasDecor = false;
	
	enum Options
	{
		Decor = 1,
		Shaped = 1<<1,
		Alpha = 1<<2
	}
}

/** The SDL screen */
class Screen : Container
{
	int width, height;
	
	Pixmap pixmap;
	
	static Screen current;
	
	SDLSurface* sdlSurface;
	SDLSurface* sdlScreen;
	
	this (int w, int h)
	{
		current = this;
		resize(w,h);
	}
	
	void resize (int w, int h)
	{
		rect = Rect(0,0,w,h);
		pixmap = new Pixmap(w,h);
		sdlScreen = SDL_SetVideoMode(w,h,32,0);
		if (sdlSurface !is null)
			SDL_FreeSurface(sdlSurface);
		sdlSurface = SDL_CreateRGBSurfaceFrom(pixmap.pixels.ptr, w, h, 32, 4*w, 0xff<<16, 0xff<<8, 0xff, 0xff<<24);
		redrawAll();
	}
	
	static this ()
	{
		SDL_Init(SDLInit.Video | SDLInit.Timer);
		mainUIThread = new Thread;
	}
	
	void redraw (Rect r)
	{
		/* Draw */
		scope Painter p = pixmap.painter;
		
		p.move(r.x1,r.y1);
		p.line(r.x2,r.y1);
		p.line(r.x2,r.y2);
		p.line(r.x1,r.y2);
		p.close();
		
		p.clip();
		
		draw(p);
		
		/* Blit */
		SDL_UpperBlit(sdlSurface, &SDLRect.from(r), sdlScreen, &SDLRect.from(r));
		SDL_UpdateRect(sdlScreen, cast(int)r.x1, cast(int)r.y1, cast(uint)(r.x2-r.x1), cast(uint)(r.y2-r.y1));
	}
}

private class Events
{
	class Motion : ThreadMessage
	{
		int x,y;
		this (int _x, int _y) {x=_x;y=_y;}
		
		void handle ()
		{
			Screen.current.mouseMotion(x,y);
		}
	}
}

/** The main UI thread */
Thread mainUIThread;

/** Enters the main GUI event loop */
void runUI ()
{
	while (true)
	{
		SDLEvent ev;
		while (SDL_PollEvent(&ev))
		{
			switch (ev.type)
			{
				case SDLEvent.QUIT:
					SDL_Quit();
					break;
				case SDLEvent.MOTION:
					mainUIThread.send(new Event.Motion(ev.motion.x, ev.motion.y));
					break;
				default: writefln("event %s", ev.type);
			}
		}
	}
}

private extern(C)
{
	enum SDLInit
	{
		Timer = 0x00000001,
		Audio = 0x00000010,
		Video = 0x00000020
		/+
			#define SDL_INIT_AUDIO          0x00000010
			#define SDL_INIT_VIDEO          0x00000020
			#define SDL_INIT_CDROM          0x00000100
			#define SDL_INIT_JOYSTICK       0x00000200
			#define SDL_INIT_NOPARACHUTE    0x00100000      /* Don't catch fatal signals */
			#define SDL_INIT_EVENTTHREAD    0x01000000      /* Not supported on all OS's */
			#define SDL_INIT_EVERYTHING     0x0000FFFF
		+/
	}
	int SDL_Init (SDLInit i);
	
	struct SDLSurface
	{
	}
	
	struct SDLRect
	{
		short x,y;
		ushort w,h;
		
		static SDLRect from (Rect r)
		{
			return SDLRect(cast(short)r.x1, cast(short)r.y1, cast(ushort)(r.x2-r.x1), cast(ushort)(r.y2-r.y1));
		}
	}
	
	struct SDLMouseMotionEvent
	{
		byte type;
		ubyte which;
		ubyte state;
		ushort x, y;
		short xrel, yrel;
		real q,w,e,r,t;
	}
	
	struct SDLMouseButtonEvent
	{
		byte type;
		ubyte which;
		ubyte button;
		ubyte state;
		ushort x,y;
	}
	
	union SDLEvent
	{
		const static int QUIT = 12;
		const static int MOTION = 4;
		const static int BUTTONDOWN = 5, BUTTONUP = 6;
		
		
		byte type;
		SDLMouseMotionEvent motion;
		SDLMouseButtonEvent button;
	}
	
	SDLSurface* SDL_SetVideoMode(int w, int h, int bpp, int flags);
	SDLSurface* SDL_CreateRGBSurfaceFrom(void *p, int w, int h, int depth, int pitch,
                                   uint r, uint g, uint b, uint a);
    void SDL_FreeSurface(SDLSurface* s);
    void SDL_UpdateRect(SDLSurface* s, int x, int y, uint w, uint h);
    void SDL_UpperBlit(SDLSurface* src, SDLRect* sr, SDLSurface* dest, SDLRect* dr);
    void SDL_Quit();
    
    int SDL_PollEvent(SDLEvent* e);
}
